package com.AdvancedDemos.集合.单列集合;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

public class 集合的并发修改异常 {
    public static void main(String[] args) {
        /**
         * 使用迭代器遍历集合时,又同时在删除集合中的数据,程序就会出现并发修改异常的错误
         */
        List<String> list = new ArrayList<>();
        list.add("王麻子");
        list.add("小李子");
        list.add("李爱华");
        list.add("张全蛋");
        list.add("晓李");
        list.add("李玉刚");
        System.out.println(list);//[王麻子, 小李子, 李爱华, 张全蛋, 小王, 李玉刚]

        //需求:找出集合中全部带"李"的名字,并从集合中删除

        for (int i = 0; i < list.size(); i++) {
            String name = list.get(i);
            if (name.contains("李")) {
                list.remove(name);
            }
        }
        System.out.println(list);//[王麻子, 李爱华, 张全蛋, 李玉刚] 删不干净,因为删除一个元素的同时,后面的元素同时前移了,遍历变量同时加1,导致跳过了一个元素,导致删不干净

/////////////////////////////////////////////////////////////////////////

        list = new ArrayList<>();
        list.add("王麻子");
        list.add("小李子");
        list.add("李爱华");
        list.add("张全蛋");
        list.add("晓李");
        list.add("李玉刚");
        System.out.println(list);

        /**
         * 使用迭代器遍历的同时,删除元素
         */
        /*Iterator<String> iterator = list.iterator();
        while (iterator.hasNext()) {
            String name = iterator.next();
            if (name.contains("李")) {
                list.remove(name);
            }
        }
        System.out.println(list);*/
        //报错 ConcurrentModificationException 并发修改异常
        //concurrent a.同时发生的,并发的
        //modification n.修改
        //该异常产生的原因与使用for循环遍历ArrayList同时删除产生漏删现象的原因一样,只不过迭代器Iterator更优雅一点,包装成了一个并发修改异常

        System.out.println("------------------------");
        //如何解决 并发修改异常 问题?
        /**
         * 对于for循环的版本,只需要每次将i--,或者倒序遍历集合,即可避免漏删的现象发生
         */
        /**
         * 对于Iterator迭代器的版本,要想避免发生并发修改异常问题
         */
        Iterator<String> iterator = list.iterator();
        while (iterator.hasNext()) {
            String name = iterator.next();
            if (name.contains("李")) {
//                list.remove(name);//不能使用list自己的remove方法,而是使用Iterator提供的remove方法
                iterator.remove();// 删除迭代器当前遍历到的数据,其底层每删除一个数据后,相当于在底层做了i--动作,从而不会出现漏删问题,也就不会产生并发修改异常问题
            }
        }
        System.out.println(list);


        /**
         * 如果使用增强的for循环 或者 forEach方法+Lambda表达式 边遍历边删除,也是会产生并发修改异常问题的,而且没有办法解决,
         * 因为forEach方法+Lambda表达式本质上就是使用的增强的for循环,而增强for循环本质上又是使用迭代器,但是又拿不到迭代器对象,调用不了迭代器对象中的remove函数,所以解决不了并发修改异常的问题
         */
        /*for (String name : list) {
            if (name.contains("李")) {
                list.remove(name);
            }
        }
        System.out.println(list);*/

        /*list.forEach(new Consumer<String>() {
            @Override
            public void accept(String name) {
                if (name.contains("李")) {
                    list.remove(name);
                }
            }
        });
        System.out.println(list);*/

        /**
         * 总结:如何避免遍历集合的同时删除数据时又不出bug?
         * 1.使用迭代器遍历结合,但用迭代器自己的删除方法删除数据即可
         * 2.如果能用for循环遍历时,可以倒序遍历并删除,或者正序遍历,但是删除元素后做i--操作
         */

    }
}
